#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <TROOT.h>
#include <TFile.h>
#include <TTree.h>
#include <TSQLServer.h>
#include <TSQLResult.h>
#include <TSQLRow.h>
#include <TClonesArray.h>

#include "GeomSvc.h"
#include "TriggerRoad.h"

using namespace std;

TSQLResult *makeQuery(TSQLServer *con, string query)
{
  //cout << query << endl;
  return con->Query(query.c_str());
}

int main(int argc, char **argv)
{
  cout << "Exporting Run: " << argv[1] << " to ROOT file: " << argv[2] << endl;

  GeomSvc *p_geomSvc = GeomSvc::instance();
  p_geomSvc->init("geometry_R962");

  Double_t mass, xF, x1, x2;
  Double_t weight;
  Double_t x0, y0, z0;
  
  Double_t px1, py1, pz1, p1;
  Double_t px2, py2, pz2, p2;

  Int_t nHodoHits1;
  Int_t detectorID1[100];
  Int_t elementID1[100];
  Double_t xp[100], yp[100];

  Int_t nHodoHits2;
  Int_t detectorID2[100];
  Int_t elementID2[100];
  Double_t xm[100], ym[100];

  Int_t nHits;
  Int_t detectorID[500];
  Int_t elementID[500];
  Double_t x[100], y[100];

  TFile *saveFile = new TFile(argv[2], "recreate");
  TTree *saveTree = new TTree("save", "save");

  saveTree->Branch("weight", &weight, "weight/D");
  saveTree->Branch("mass", &mass, "mass/D");
  saveTree->Branch("xF", &xF, "xF/D");
  saveTree->Branch("x1", &x1, "x1/D");
  saveTree->Branch("x2", &x2, "x2/D");
  saveTree->Branch("x0", &x0, "x0/D");
  saveTree->Branch("y0", &y0, "y0/D");
  saveTree->Branch("z0", &z0, "z0/D");
  
  saveTree->Branch("nHits", &nHits, "nHits/I");
  saveTree->Branch("detectorID", detectorID, "detectorID[nHits]/I");
  saveTree->Branch("elementID", elementID, "elementID[nHits]/I");
  saveTree->Branch("x", x, "x[nHits]/D");
  saveTree->Branch("y", y, "y[nHits]/D");

  saveTree->Branch("px1", &px1, "px1/D");
  saveTree->Branch("py1", &py1, "py1/D");
  saveTree->Branch("pz1", &pz1, "pz1/D");
  saveTree->Branch("p1", &p1, "p1/D");

  saveTree->Branch("nHodoHits1", &nHodoHits1, "nHodoHits1/I");
  saveTree->Branch("detectorID1", &detectorID1, "detectorID1[nHodoHits1]/I");
  saveTree->Branch("elementID1", &elementID1, "elementID1[nHodoHits1]/I");
  saveTree->Branch("xp", &xp, "xp[nHodoHits1]/D");
  saveTree->Branch("yp", &yp, "yp[nHodoHits1]/D");

  saveTree->Branch("px2", &px2, "px2/D");
  saveTree->Branch("py2", &py2, "py2/D");
  saveTree->Branch("pz2", &pz2, "pz2/D");
  saveTree->Branch("p2", &p2, "p2/D");

  saveTree->Branch("nHodoHits2", &nHodoHits2, "nHodoHits2/I");
  saveTree->Branch("detectorID2", &detectorID2, "detectorID2[nHodoHits2]/I");
  saveTree->Branch("elementID2", &elementID2, "elementID2[nHodoHits2]/I");
  saveTree->Branch("xm", &xm, "xm[nHodoHits2]/D");
  saveTree->Branch("ym", &ym, "ym[nHodoHits2]/D");

  ///Connect to the SQL databases
  //TSQLServer *con = TSQLServer::Connect("mysql://seaquel.physics.illinois.edu", "seaguest","qqbar2mu+mu-");
  TSQLServer *con = TSQLServer::Connect("mysql://140.109.102.242", "admin","scientific");
  const char *buf1 = "SELECT trackID1,trackID2,sigWeight,mass,xF,xB,xT FROM %s.mDimuon WHERE acceptHodoAll=1 AND sigWeight>0.0001 ORDER BY eventID LIMIT %d";
  const char *buf2 = "SELECT x0,y0,z0,px0,py0,pz0 FROM %s.mTrack WHERE trackID IN (%d, %d) ORDER BY trackID";
  const char *buf3 = "SELECT trackID,detectorName,elementID,xAtDigiPlane,yAtDigiPlane FROM %s.mDigiHit WHERE trackID IN (%d, %d) AND (detectorName LIKE 'H__'"
   " OR detectorName LIKE 'H4___') ORDER BY trackID,zAtDigiPlane";

  char query[500];
  sprintf(query, buf1, argv[1], atoi(argv[3])); 
  TSQLResult *res_dimuon = makeQuery(con, query);

  UInt_t nEntries = res_dimuon->GetRowCount();
  cout << "Totally " << nEntries << " dimuon pairs in this run" << endl;
  for(UInt_t i = 0; i < nEntries; i++)
    {
      if(i % 1000 == 0)
	{
	  cout << "Converting dimuon pair " << i << endl;
	}

      TSQLRow *row_dimuon = res_dimuon->Next();

      Int_t trackID1 = atoi(row_dimuon->GetField(0));
      Int_t trackID2 = atoi(row_dimuon->GetField(1));
      weight = atof(row_dimuon->GetField(2));
      mass = atof(row_dimuon->GetField(3));
      xF = atof(row_dimuon->GetField(4));
      x1 = atof(row_dimuon->GetField(5));
      x2 = atof(row_dimuon->GetField(6));

      sprintf(query, buf2, argv[1], trackID1, trackID2);
      TSQLResult *res_track = makeQuery(con, query);

      Int_t nTracks = res_track->GetRowCount();
      if(nTracks != 2)
	{
	  cout << "Error: more than 2 tracks in one event! " << endl;
	}

      for(Int_t j = 0; j < nTracks; j++)
	{
	  TSQLRow *row_track = res_track->Next();
	
    	  x0 = atof(row_track->GetField(0));
          y0 = atof(row_track->GetField(1));
          z0 = atof(row_track->GetField(2));
          if(j == 0)
	    {
	      px1 = atof(row_track->GetField(3));
	      py1 = atof(row_track->GetField(4));
	      pz1 = atof(row_track->GetField(5));
              p1 = sqrt(px1*px1 + py1*py1 + pz1*pz1);
	    }	
          else
	    {
	      px2 = atof(row_track->GetField(3));
	      py2 = atof(row_track->GetField(4));
	      pz2 = atof(row_track->GetField(5));
	      p2 = sqrt(px2*px2 + py2*py2 + pz2*pz2);
	    }	      

	  delete row_track;
	}

      sprintf(query, buf3, argv[1], trackID1, trackID2);
      TSQLResult *res_hodo = makeQuery(con, query);

      Int_t nHodoHitsAll = res_hodo->GetRowCount();
      nHodoHits1 = 0;
      nHodoHits2 = 0;
      nHits = 0;
      for(Int_t j = 0; j < nHodoHitsAll; j++)
	{
	  TSQLRow *row_hodo = res_hodo->Next();

	  Int_t trackID = atoi(row_hodo->GetField(0));
	  string detectorName(row_hodo->GetField(1));
	  Int_t eID = atoi(row_hodo->GetField(2));
	  Double_t x_pos = atof(row_hodo->GetField(3));
	  Double_t y_pos = atof(row_hodo->GetField(4));
	  p_geomSvc->toLocalDetectorName(detectorName, eID);
	  Int_t dID = p_geomSvc->getDetectorID(detectorName);

	  detectorID[nHits] = dID;
	  elementID[nHits] = eID;
          x[nHits] = x_pos;
	  y[nHits] = y_pos;
	  nHits++;

	  if(trackID == trackID1)
	    {
	      detectorID1[nHodoHits1] = dID;
	      elementID1[nHodoHits1] = eID;
	      xm[nHodoHits1] = x_pos;
	      ym[nHodoHits1] = y_pos;
	    
	      ++nHodoHits1;
	    }
	  else if(trackID == trackID2)
	    {
	      detectorID2[nHodoHits2] = dID;
              elementID2[nHodoHits2] = eID;
	      xp[nHodoHits2] = x_pos; 
	      yp[nHodoHits2] = y_pos; 
	      
	      ++nHodoHits2;
	    }

	  delete row_hodo;
	}

      saveTree->Fill();

      delete row_dimuon;
      delete res_track;
      delete res_hodo;
    }

  delete res_dimuon;
  delete con;

  saveFile->cd();
  saveTree->Write();
  saveFile->Close();
  
  return 1;
}
